package hotciv.view;

import hotciv.common.GameImpl;
import hotciv.framework.*;

import java.awt.*;
import java.util.*;

import minidraw.framework.*;
import minidraw.standard.*;
import minidraw.standard.handlers.*;

/** CivDrawing is a specialized Drawing (model component) from
 * MiniDraw that dynamically builds the list of Figures for MiniDraw
 * to render the Unit and other information objects that are visible
 * in the Game instance.
 *
 * This is a TEMPLATE for the dSoftArk Exercise! This means
 * that it is INCOMPLETE and that there are several options
 * for CLEANING UP THE CODE when you add features to it!

   This source code is from the book 
     "Flexible, Reliable Software:
       Using Patterns and Agile Development"
     published 2010 by CRC Press.
   Author: 
     Henrik B Christensen 
     Computer Science Department
     Aarhus University
   
   This source code is provided WITHOUT ANY WARRANTY either 
   expressed or implied. You may study, use, modify, and 
   distribute it for non-commercial purposes. For any 
   commercial use, see http://www.baerbak.com/
 
*/

public class CivDrawing extends StandardDrawing
  implements Drawing, GameObserver {

  /** the Game instance that this UnitDrawing is going to render units
   * from */
  protected Game game;
  
  public CivDrawing( DrawingEditor editor, Game game ) {
    super();
    this.game = game;

    // register this unit drawing as listener to any game state
    // changes...
    game.addObserver(this);
    // ... and build up the set of figures associated with
    // units in the game.
    defineUnitMap();
    // cities in the game
    defineCityMap();
    // and the set of 'icons' in the status panel
    defineIcons();
  }
  
  /** The UnitDrawing should not allow client side
   * units to add and manipulate figures; only figures
   * that renders game objects are relevant, and these
   * should be handled by observer events from the game
   * instance. Thus this method is 'killed'.
   */
  public Figure add(Figure arg0) {
    throw new RuntimeException("Should not be used...");
  }

  /** store all moveable figures visible in this drawing = units */
  protected Map<Unit,UnitFigure> figureMap = null;
   
  /** erase the old list of units, and build a completely new
   * one from scratch by iterating over the game world and add
   * Figure instances for each unit in the world.
   */
  private void defineUnitMap() {
    // ensure no units of the old list are accidental in
    // the selection!
    clearSelection();

    figureMap = new HashMap<Unit,UnitFigure>();
    Position p;
    for ( int r = 0; r < GameConstants.WORLDSIZE; r++ ) {
      for ( int c = 0; c < GameConstants.WORLDSIZE; c++ ) {
        p = new Position(r,c);
        Unit unit = game.getUnitAt(p);
        if ( unit != null ) {
          String type = unit.getTypeString();
          // convert the unit's Position to (x,y) coordinates
          Point point = new Point( GfxConstants.getXFromColumn(p.getColumn()),
                                   GfxConstants.getYFromRow(p.getRow()) );
          UnitFigure unitFigure =
            new UnitFigure( type, point, unit );
          unitFigure.addFigureChangeListener(this);
          figureMap.put(unit, unitFigure);

          // also insert in superclass list as it is
          // this list that is iterated by the
          // graphics rendering algorithms
          super.add(unitFigure);
          
        }
      }
    }
  }
  
  /** store all city figures  */
  protected Map<City,CityFigure> cityFigureMap = null;
   
  /** erase the old list of units, and build a completely new
   * one from scratch by iterating over the game world and add
   * Figure instances for each unit in the world.
   */
  private void defineCityMap() {
    // ensure no units of the old list are accidental in
    // the selection!
    clearSelection();
    cityFigureMap = new HashMap<City,CityFigure>();
    for ( int r = 0; r < GameConstants.WORLDSIZE; r++ ) {
      for ( int c = 0; c < GameConstants.WORLDSIZE; c++ ) {
        City city = game.getCityAt(new Position(r,c));
        if ( city != null ) {
        	CityFigure cityFigure = new CityFigure( city,  new Point( GfxConstants.getXFromColumn(c),  GfxConstants.getYFromRow(r) ) );
        	cityFigureMap.put(city, cityFigure);

          // also insert in superclass list as it is
          // this list that is iterated by the
          // graphics rendering algorithms
          super.add(cityFigure);
        }
      }
    }
  }
  
  private String getAgeString(int age) {
	  return age<0 ? Math.abs(age)+" BC" : age+" AC";
  }

  private ImageFigure turnShieldIcon;
  private TextFigure ageField;
  private ImageFigure cityShieldIcon;
  private ImageFigure cityWorkforceFocusField;
  private ImageFigure cityProductionField;
  private ImageFigure unitShieldIcon;
  private TextFigure unitMovesLeftField;
  private void defineIcons() {
    // very much a template implementation :)
    turnShieldIcon = new ImageFigure( getPlayerShield(game.getPlayerInTurn()), new Point( GfxConstants.TURN_SHIELD_X,  GfxConstants.TURN_SHIELD_Y ) ); 
    // insert in superclass figure list to ensure graphical
    // rendering.
    super.add(turnShieldIcon);

    ageField = new TextFigure(getAgeString(game.getAge()), new Point(GfxConstants.AGE_TEXT_X,  GfxConstants.AGE_TEXT_Y) );
    ageField.setFont(new Font("Arial", Font.BOLD, 22));
    super.add(ageField);
    
    cityShieldIcon = new ImageFigure(); 
    
    cityWorkforceFocusField = new ImageFigure(GfxConstants.NOTHING, new Point(GfxConstants.WORKFORCEFOCUS_X,  GfxConstants.WORKFORCEFOCUS_Y) );
    super.add(cityWorkforceFocusField);
    
    cityProductionField = new ImageFigure(GfxConstants.NOTHING, new Point(GfxConstants.CITY_PRODUCTION_X,  GfxConstants.CITY_PRODUCTION_Y) );
    super.add(cityProductionField);
    
    
    unitShieldIcon = new ImageFigure(); 
    
    unitMovesLeftField = new TextFigure("", new Point(GfxConstants.UNIT_COUNT_X,  GfxConstants.UNIT_COUNT_Y) );
    super.add(unitMovesLeftField);
    
    
  }
  
  private String getPlayerShield(Player player) {
	  String shieldname = GfxConstants.RED_SHIELD;
	  if ( player == Player.BLUE ) { shieldname = GfxConstants.BLUE_SHIELD; }
	  return shieldname;
  }
  
  private void emptyInspectionBox() {
	  super.remove(cityShieldIcon);
	  super.remove(unitShieldIcon);
	  cityWorkforceFocusField.set(GfxConstants.NOTHING, new Point(GfxConstants.WORKFORCEFOCUS_X,  GfxConstants.WORKFORCEFOCUS_Y));
	  cityProductionField.set(GfxConstants.NOTHING, new Point(GfxConstants.CITY_PRODUCTION_X,  GfxConstants.CITY_PRODUCTION_Y));
	  unitMovesLeftField.setText("");
  }
 
  // === Observer Methods ===

  public void worldChangedAt(Position pos) {
    System.out.println( "UnitDrawing: world changes at "+pos);
    clearSelection();
    // this is a really brute-force algorithm: destroy
    // all known units and build up the entire set again
    for ( Figure f : figureMap.values() ) {
      super.remove(f);
    }
    defineUnitMap();
    for ( Figure f : cityFigureMap.values() ) {
      super.remove(f);
    }
    defineCityMap();
  }

  public void turnEnds(Player nextPlayer, int age) {
    System.out.println( "UnitDrawing: turnEnds for "+ nextPlayer+" at "+age );
    turnShieldIcon.set( getPlayerShield(nextPlayer),new Point( GfxConstants.TURN_SHIELD_X,  GfxConstants.TURN_SHIELD_Y ) );
    
    ageField.setText(getAgeString(game.getAge()));
  }

  public void tileFocusChangedAt(Position position) {
    System.out.println( "UnitDrawing: tileFocusChanged at "+position );
    emptyInspectionBox();
    Unit u = game.getUnitAt(position);
    City c = game.getCityAt(position);
    if (u!=null) {
    	unitShieldIcon.set(getPlayerShield(u.getOwner()), new Point(GfxConstants.UNIT_SHIELD_X,  GfxConstants.UNIT_SHIELD_Y) );
    	super.add(unitShieldIcon);
    	int movesLeft = ((GameImpl) game).movesLeftForUnit(u, position);
    	unitMovesLeftField.setText(""+movesLeft);
    }
    else if (c!=null) {
    	cityShieldIcon.set(getPlayerShield(c.getOwner()), new Point(GfxConstants.CITY_SHIELD_X,  GfxConstants.CITY_SHIELD_Y) );
    	super.add(cityShieldIcon);
    	cityWorkforceFocusField.set(c.getWorkforceFocus(), new Point(GfxConstants.WORKFORCEFOCUS_X,  GfxConstants.WORKFORCEFOCUS_Y));
    	cityProductionField.set(c.getProduction(), new Point(GfxConstants.CITY_PRODUCTION_X,  GfxConstants.CITY_PRODUCTION_Y));
    }
  }
}
